#include <device.h>
static uint32_t *rtc_port_base = NULL;
static uint32_t *uptime_port_base = NULL;

static uint64_t boot_time = 0;

static uint64_t get_time_internal() {
  struct timespec now;
  clock_gettime(CLOCK_MONOTONIC_COARSE, &now);
  uint64_t us = now.tv_sec * 1000000 + now.tv_nsec / 1000;
  return us;
}

uint64_t get_time() {
  if (boot_time == 0) boot_time = get_time_internal();
  uint64_t now = get_time_internal();
  return now - boot_time;
}


static void rtc_io_handler(uint32_t offset, int len, bool is_write) {
  fflush(stdout);
  assert(offset == 0 || offset == 4);
  if (!is_write && offset == 0) {
    uint64_t us = get_time_internal();
    rtc_port_base[0] = (uint32_t)us;
    rtc_port_base[1] = us >> 32;
  }
}

static void uptime_io_handler(uint32_t offset, int len, bool is_write) {
  assert(offset == 0 || offset == 4);
  if (!is_write && offset == 0) {
    uint64_t us = get_time();
    uptime_port_base[0] = (uint32_t)us;
    uptime_port_base[1] = us >> 32;
  }
}


void init_timer() {
  rtc_port_base = (uint32_t *)new_space(8);
  uptime_port_base = (uint32_t *)new_space(8);
  add_mmio_map("rtc", CONFIG_RTC_BASE, rtc_port_base, 8, rtc_io_handler);
  add_mmio_map("uptime", CONFIG_UPTIME_BASE, uptime_port_base, 8, uptime_io_handler);
}
